package menu
{
	import adobe.utils.CustomActions;
	
	import com.*;
	import com.Logging.CGSClientConstants;
	import com.Logging.ClientAction;
	import com.Logging.ClientActionType;
	
	import data.*;
	
	import events.*;
	
	import flash.display.Bitmap;
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.text.TextField;
	import flash.utils.Dictionary;
	import flash.utils.Timer;
	
	import org.flixel.*;
	
	import ui.button.GCButton;
	import ui.list.*;
	import ui.popup.GCBuyPopup;
	import ui.popup.GCConfirmationPopup;
	import ui.popup.GCSellPopup;
	import ui.popup.GCTextPopup;
	import ui.textfield.GCTextField;
	

	
	/**
	 * ...
	 * @author Jason Won
	 */
	public class GCMarketMenu extends Sprite implements GCSuperMenu
	{		
		private static const NUMBER_RANDOM_SALES:uint = 3;
		
		// Inventory lists
		private var _shipInventoryListDisplay:GCItemScrollList;
		private var _warehouseListDisplay:GCItemScrollList;
		private var _playerSalesListDisplay:GCItemScrollList;
		private var _marketSalesListDisplay:GCSalesScrollList;
		
		// Description Box Labels
		private var _marketSalesLabel:GCTextField;
		private var _resourceDisplayText:TextField;
		private var _resourceDisplayArea:Sprite;
		private var _resourceAvgPriceText:TextField;
		private var _resourceAvgPriceArea:Sprite;
		
		// Various menu Buttons
		private var _exitButton:GCButton;
		private var _buyButton:GCButton;
		private var _sellButton:GCButton;
		private var _removeSaleButton:GCButton;
		
		// Transfer Helpers
		private var _selectedItemUI:GCItemListUI;
		private var _selectedItem:GCItem;
		
		// Popup components
		private var _buyPopup:GCBuyPopup;
		private var _sellPopup:GCSellPopup;
		
		// Tab Buttons
		private var _shipInventoryButton:GCButton;
		private var _warehouseInventoryButton:GCButton;
		private var _playerSalesButton:GCButton;
		private var _currentList:ScrollList;
		
		private var _currentLocation:uint;
		
		/**
		 * Constructor
		 */
		public function GCMarketMenu() 
		{
			// Background
			var background:Bitmap = GCResources.getResource("main_background");
			this.addChild(background);
			
			// Create list components
			_shipInventoryListDisplay = new GCItemScrollList(300, 400, true);
			_warehouseListDisplay = new GCItemScrollList(300, 400, true);
			_playerSalesListDisplay = new GCItemScrollList(300, 400, true);
			_marketSalesListDisplay = new GCSalesScrollList(300, 400);
			
			// Create description box components
			_resourceAvgPriceText = new TextField();
			_resourceAvgPriceArea = new Sprite();
			_resourceDisplayText = new TextField();
			_resourceDisplayArea = new Sprite();
			
			// Create menu button components
			_buyButton = new GCButton(onBuyClick);		
			_sellButton = new GCButton(onSellClick);
			_exitButton = new GCButton(onExitClick);
			_removeSaleButton = new GCButton(onRemoveSale);
			
			// Create popup components
			_buyPopup = new GCBuyPopup();
			_sellPopup = new GCSellPopup();
			
			// Create tab buttons
			_shipInventoryButton = new GCButton(onClickTab);
			_warehouseInventoryButton = new GCButton(onClickTab);
			_playerSalesButton = new GCButton(onClickTab);
			_currentList = _warehouseListDisplay;
			
			// Labels
			_marketSalesLabel = new GCTextField();
			
			init();
		}

		private function init():void
		{	
			// Listeners for Popups
			_buyPopup.addEventListener(GCEvent.BUY_CONFIRM_EVENT, onBuyConfirm);
			_buyPopup.addEventListener(GCEvent.CANCEL_EVENT, onBuyCancel);
			_sellPopup.addEventListener(GCEvent.SELL_CONFIRM_EVENT, onSellConfirm);
			_sellPopup.addEventListener(GCEvent.CANCEL_EVENT, onSellCancel);
			
			// Listeners for displays
			_marketSalesListDisplay.addEventListener(GCEvent.LIST_ITEM_SELECTED_EVENT, onBuyClick);
			_warehouseListDisplay.addEventListener(GCEvent.LIST_ITEM_SELECTED_EVENT, onSellClick);
			_playerSalesListDisplay.addEventListener(GCEvent.LIST_ITEM_SELECTED_EVENT, onRemoveClick);
			
			/*
			// Create buttons
			_buyButton.loadGraphic(GCResources.plate, 100, 30);
			_buyButton.loadText("Buy");
			_buyButton.x = 500;
			_buyButton.y = 450;
			
			_sellButton.loadGraphic(GCResources.plate, 100, 30);
			_sellButton.loadText("Sell");
			_sellButton.x = 140;
			_sellButton.y = 450;
			*/
			_exitButton.loadGraphic(GCResources.plate, 100, 30);
			_exitButton.loadText("Exit Market");
			_exitButton.x = FlxG.width / 2 - _exitButton.width / 2;
			_exitButton.y = 480;
			/*
			_removeSaleButton.loadGraphic(GCResources.plate, 100, 30);
			_removeSaleButton.loadText("Remove Sale");
			_removeSaleButton.x = _sellButton.x;
			_removeSaleButton.y = _sellButton.y;
			*/
			// Create tab navigation buttons
			_shipInventoryButton.loadGraphic(GCResources.plate, 100, 30);
			_shipInventoryButton.loadText("Ship");
			_shipInventoryButton.x = 50;
			_shipInventoryButton.y = 0;
			
			_warehouseInventoryButton.loadGraphic(GCResources.plate, 100, 30);
			_warehouseInventoryButton.loadText("Warehouse");
			_warehouseInventoryButton.x = _shipInventoryButton.x + _shipInventoryButton.width;
			_warehouseInventoryButton.y = _shipInventoryButton.y;

			_playerSalesButton.loadGraphic(GCResources.plate, 100, 30);
			_playerSalesButton.loadText("My Sales");
			_playerSalesButton.x = _warehouseInventoryButton.x + _warehouseInventoryButton.width;
			_playerSalesButton.y = _shipInventoryButton.y;
			
			/*
			var resourceNameLabel:TextField = new TextField();
			resourceNameLabel.text = "Name of Item";
			_resourceDisplayArea.x = this.width - 100;
			_resourceDisplayArea.y = 0;
			_resourceDisplayArea.addChild(resourceNameLabel);
			_resourceDisplayArea.addChild(_resourceDisplayText);
			
			var avgPriceLabel:TextField = new TextField();
			avgPriceLabel.text = "Average Buying Price";
			_resourceAvgPriceArea.x = this.width - 100;
			_resourceAvgPriceArea.y = _resourceDisplayArea.y + _resourceDisplayArea.height + 30;
			_resourceAvgPriceArea.addChild(avgPriceLabel);
			_resourceAvgPriceArea.addChild(_resourceAvgPriceText);
			*/
			
			// List display Attributes
			_shipInventoryListDisplay.x = 50;
			_shipInventoryListDisplay.y = 30;
			_warehouseListDisplay.x = 50;
			_warehouseListDisplay.y = 30;
			_playerSalesListDisplay.x = 50;
			_playerSalesListDisplay.y = 30;
			_marketSalesListDisplay.x = 400;
			_marketSalesListDisplay.y = 30;
			
			// Labels
			_marketSalesLabel.setStyle(GCTextField.TEXT_TYPE_HIGHLIGHT);
			_marketSalesLabel.setXY(_marketSalesListDisplay.x, 0);
			_marketSalesLabel.text = "Market Sales";
			
			// Add all of the objects to the screen
			this.addChild(_marketSalesLabel);
			this.addChild(_resourceAvgPriceArea);
			this.addChild(_resourceDisplayArea);
			this.addChild(_exitButton);
			//this.addChild(_buyButton);
			//this.addChild(_sellButton);
			this.addChild(_warehouseListDisplay);
			this.addChild(_marketSalesListDisplay);
			this.addChild(_shipInventoryButton);
			this.addChild(_warehouseInventoryButton);
			this.addChild(_playerSalesButton);
		}
		
		/**
		 * At this point we will populate the menus with the item's on the
		 * market at this city.
		 */
		public function openMenu(playerInventory:GCInventory, warehouseInventory:GCInventory, playerSales:GCInventory,location:uint):void
		{
			_currentLocation = location;
			
			_shipInventoryListDisplay.loadInventory(playerInventory);
			_warehouseListDisplay.loadInventory(warehouseInventory);
			_playerSalesListDisplay.loadInventory(playerSales);
			_marketSalesListDisplay.loadInventory(new GCInventory(new Vector.<GCItem>, 0, int.MAX_VALUE));

			(GCPlayState.tutorialSequence.currentTutorialStage > GCTutorial.STAGE_FIRST_ORDER) ?
				_shipInventoryButton.enable() : _shipInventoryButton.disable();
			
			(GCPlayState.tutorialSequence.currentTutorialStage > GCTutorial.STAGE_START_CITY) ?
				_buyButton.enable() : _buyButton.disable();	
			
			if (GCPlayState.tutorialSequence.currentTutorialStage < GCTutorial.STAGE_ON_RETURN)
			{
				var salesList:Vector.<GCItem> = generateFakeSales(GCPlayState.tutorialSequence.currentTutorialStage);
				for each (var saleItem:GCItem in salesList)
				{
					_marketSalesListDisplay.pushNewSale(saleItem);
				}
				//loadMarketSalesDisplay();
			}
			else
			{
				if (!GCConstants.DEBUG_MODE)
				{
					loadMarketSalesDisplay();
				}
				
				// DEBUG
				var dummySale:GCItem;
				for (var i:int = 1; i < NUMBER_RANDOM_SALES; i++ )
				{
					dummySale = randomSaleGenerator();
					dummySale.invItemId = i * 999;
					_marketSalesListDisplay.addSale(dummySale);
				}
				_marketSalesListDisplay.pushNewSale(new GCItem(99999, GCItemData.ITEM_FOOD, Math.floor(Math.random() * 10) + 5, 
					GCConstants.COMPUTER_SELLER, GCConstants.COMPUTER_NAME, Math.floor(Math.random() * 30) + 50, true));
			}
		}		
		
		/**
		 * Clean up this menu
		 */
		public function closeMenu():void
		{
			_shipInventoryListDisplay.removeAll();
			_warehouseListDisplay.removeAll();
			_playerSalesListDisplay.removeAll();
			_marketSalesListDisplay.removeAll();
			
			/*
			 * Remove any popups that may have still been on screen
			 */
			if (_buyPopup.parent != null)
			{
				onBuyCancel();
			}
			
			if (_sellPopup.parent != null)
			{
				onSellCancel();
			}
		}
				
		//----------------------------------------------------------------------
		//	PRIVATE FUNCTIONS
		//----------------------------------------------------------------------
		
		/** Tab Navigation Handlers **/
		private function onClickTab(event:MouseEvent):void
		{
			this.removeChild(_currentList);
			switch(event.currentTarget)
			{
				case _shipInventoryButton:
					this.addChild(_shipInventoryListDisplay);
					_currentList = _shipInventoryListDisplay;
					/*
					_sellButton.disable();
					if (_sellButton.parent != this)
					{
						this.addChild(_sellButton);
						this.removeChild(_removeSaleButton);
					}*/
					return;
				case _warehouseInventoryButton:
					this.addChild(_warehouseListDisplay);
					_currentList = _warehouseListDisplay;
					/*_sellButton.enable();
					if (_sellButton.parent != this)
					{
						this.addChild(_sellButton);
						this.removeChild(_removeSaleButton);
					}*/
					return;
				case _playerSalesButton:
					this.addChild(_playerSalesListDisplay);
					_currentList = _playerSalesListDisplay;
					/*if (_removeSaleButton.parent != this)
					{
						this.addChild(_removeSaleButton);
						this.removeChild(_sellButton);
					}*/
					return;
				default:
					this.addChild(_warehouseListDisplay);
					_currentList = _warehouseListDisplay;
					_sellButton.enable();
					/*if (_sellButton.parent != this)
					{
						this.addChild(_sellButton);
						this.removeChild(_removeSaleButton);
					}*/
			}
		}
		
		// Problem loading up
		private function loadMarketSalesDisplay():void
		{
			var allSales:Vector.<GCItem> = new Vector.<GCItem>();;
			
			//DATABASE CALL- get all sales listings at this city
			GCUtil.getSalesListing(_currentLocation, function(code:uint, data:Object):void
			{
				//var listings:Object = data["details"];
				
				for each (var item:Object in data["details"])
				{
					var invItemId:uint = item["id"];
					var itemId:uint = item["itemId"];
					var saleQuantity:uint = item["saleQty"];
					var pricePer:uint = item["salePrice"];
					var sellerId:uint = item["pid"];
					var sellerName:String = item["name"];
					var sellerXP:uint = item["xp"];
					
					var sellerLevel:uint = GCExperienceData.getLevelFromXP(sellerXP);
					
					//trace("Getting sale " + invItemId + " " + itemId + " " + saleQuantity + " " + pricePer + " " + sellerId + " " + sellerName + " " + sellerLevel);
					var itemObject:GCItem = new GCItem(invItemId, itemId, saleQuantity, sellerId, sellerName, pricePer, true, sellerLevel);
					if (sellerId != GCPlayState.getPlayerId())
					{
						allSales.push(itemObject);
					}
					else
					{
						//trace("FOUND ONE OF YOUR SALES!!!!!");
					}
				}
				
				checkLoadingComplete();
			});
			
			// Check if all data necessary to populate the market sales display has been loaded
			function checkLoadingComplete():void
			{
				// Loop through all the items and filter out ones that belong to you
				// Do not allow player to buy their own stuff on sale
				for each (var saleListing:GCItem in allSales)
				{
					_marketSalesListDisplay.pushNewSale(saleListing);
				}
			}
		}
		
		//----------------------------------------------------------------------
		//	EVENT HANDLER
		//----------------------------------------------------------------------
		
		/* 
		 * Dispatches event to close the menu
		 * */
		private function onExitClick(event:Event):void
		{
			dispatchEvent(new GCEvent(GCEvent.EXIT_MENU_EVENT));
		}
		
		/* 
		 * Reacts to the buy button
		 * Opens up the popup for buying confirmation
		 * */
		private function onBuyClick(event:GCEvent):void
		{
			_selectedItemUI = _marketSalesListDisplay.selected;
			
			if (_selectedItemUI == null)
			{
				trace("Selected item was null!!!!!!");
				// No item selected; just return and don't open popup
				return;
			}
			
			_selectedItem = _selectedItemUI.reference;
			
			var notification:GCTextPopup;
			// Check if the user has enough money
			if (GCPlayState.getPlayerGold() < _selectedItem.price)
			{
				// The player does not have enough gold
				notification = new GCTextPopup("You do not have enough gold to buy this item.", GCPlayState.enableScreen);
				GCPlayState.disableScreen(notification);
				return;
			}
			
			// Capacity Check
			var quantityLimit:int = Math.floor(Math.min(_selectedItem.quantity, _shipInventoryListDisplay.remainingCapacity(), (GCPlayState.getPlayerGold() / _selectedItem.price)));
			if (quantityLimit <= 0) 
			{
				// The player does not have enough room
				notification = new GCTextPopup("You have no more room on your ship!", GCPlayState.enableScreen);
				GCPlayState.disableScreen(notification);
				return;
			}			
			
			// Open up the buy popup
			_buyPopup.initializePopup(quantityLimit, _selectedItem.price, GCItemData.getNameFromId(_selectedItem.itemId));
			_buyPopup.x = FlxG.width / 2 - _buyPopup.width / 2;
			_buyPopup.y = FlxG.height / 2 - _buyPopup.height / 2;
			GCPlayState.disableScreen(_buyPopup);
		}
		
		/**
		 * Handles when the player successfilly confirms a buy.
		 */
		private function onBuyConfirm(event:Event):void
		{
			/*
			We must first get the amount of goods purchased
			and the price the user paid.
			*/
			var quantity:int = _buyPopup.quantityBought;
			var cost:int = _buyPopup.totalCost;
			
			if (GCConstants.LOGGING_DATA)
			{
				// Log the transaction
				var o:Object = new Object();
				o["itemId"] = _selectedItem.itemId;
				o["qty"] = _selectedItem.quantity;
				o["price"] = _selectedItem.price;
				GCPlayState.logger.LogAction(new ClientAction(ClientActionType.BUY, o));
			}
			
			
			var lidToPlace:uint = (GCPlayState.tutorialSequence.currentTutorialStage > GCTutorial.STAGE_FIRST_ORDER) ?
				GCCityData.CITY_SHIP : GCPlayState.getCurrentCity().getId();	
			
			// Go in here if we are at a tutorial or buying from a computer seller
			if (GCPlayState.tutorialSequence.currentTutorialStage < GCTutorial.STAGE_ON_RETURN || _selectedItem.sellerId == GCConstants.COMPUTER_SELLER)
			{
				if (GCConstants.DEBUG_MODE)
				{
					onUpdateLists(0);
					onTutorialCheck();
				}
				else
				{
					// Tutorial buying, sold goods are computer generated (also handles non-tutorial where sales are computer generated)
					GCUtil.addToInventory(GCPlayState.getPlayerId(), _selectedItem.itemId, lidToPlace, quantity, function (code:uint, data:Object):void
					{
						var invAddItemId:uint = data["id"];
						onUpdateLists(invAddItemId);

						onTutorialCheck();
					});
				}
				
				function onTutorialCheck():void
				{
					// Update gold
					GCPlayState.changePlayerGold( -1 * cost);
					
					/*
					 * Roy--tutorial
					 * For the goals in which a player is required to purchase some quantity of
					 * a specific good. (Tutorial buying is a bit different, we will just want to do
					 * an add to their inventory)
					 */
					if (GCPlayState.tutorialSequence.currentTutorialStage == GCTutorial.STAGE_FIRST_ORDER)
					{
						trace("GCMarketMenu-- attempting to resolve first order");
						checkIfEnoughBought(GCQuestData.QUEST_TEMPLATE_TUTORIAL_1, _selectedItem.itemId);
						
					}
					else if (GCPlayState.tutorialSequence.currentTutorialStage == GCTutorial.STAGE_FIRST_JOURNEY)
					{
						/*
						 * Checking that they have purchased at least the specified amount of food from
						 * the market
						 */
						checkIfEnoughBought(GCQuestData.QUEST_TEMPLATE_TUTORIAL_3, _selectedItem.itemId);
						
						/*
						 * Checking that they have purchased enough goods to satisfy a different customer's order 
						 */
						checkIfEnoughBought(GCQuestData.QUEST_TEMPLATE_TUTORIAL_4, _selectedItem.itemId);
					}
					else if (GCPlayState.tutorialSequence.currentTutorialStage == GCTutorial.STAGE_AT_NEW_CITY)
					{
						/*
						 * Checking that they have purchased enough cotton at other town.
						 */
						checkIfEnoughBought(GCQuestData.QUEST_TEMPLATE_TUTORIAL_7, _selectedItem.itemId);
					}
					else if (GCPlayState.tutorialSequence.currentTutorialStage >= GCTutorial.STAGE_ON_RETURN)
					{
						GCPlayState.increaseExperience(Math.min(quantity * _selectedItem.price, GCPlayState.playerData.playerLevel * _selectedItem.price * 2) as int);
					}
					
					// Clear the selections
					_selectedItem = null;
					_selectedItemUI = null;
				}
			}
			else
			{
				// Regular buying from human players
				if (GCConstants.DEBUG_MODE)
				{
					onUpdateLists(0);
							
					// Also update gold
					GCPlayState.changePlayerGold( -1 * cost);
					
					// Clear the selections
					_selectedItem = null;
					_selectedItemUI = null;
				}
				else
				{
					// TODO: Fix issue, somehow saleQty on DB is greater than actual Qty
					//trace("TRIED TO BUY SOMETHING " + quantity + " " +  _selectedItem.invItemId);
					GCUtil.buyItem(GCPlayState.playerData.getPlayerId(), _selectedItem.invItemId, _selectedItem.itemId, _selectedItem.price,
					quantity, lidToPlace, _selectedItem.sellerId, function (code:uint, data:Object):void
					{
						var invBuyItemId:uint = data["id"];
						trace("Attempted buy " + _selectedItem.invItemId);
						if (code == 0)
						{
							onUpdateLists(invBuyItemId);
							
							// Also update gold (only on ui though)
							GCPlayState.changePlayerGold( -1 * cost, false);
						}
						else if (code == 1)
						{
							GCPlayState.disableScreen(new GCTextPopup("Someone else has already bought this item", GCPlayState.enableScreen));
						}
						else
						{
							trace(code);
							// SQL exception
						}
						
						// Clear the selections
						_selectedItem = null;
						_selectedItemUI = null;
					});
				}
				GCPlayState.increaseExperience(Math.min(quantity * _selectedItem.price, GCPlayState.playerData.playerLevel * _selectedItem.price * 2) as int);
			}
			
			
			// Nested function that deals with updating the lists and logical inventory structures
			function onUpdateLists(invItemId:uint):void
			{
				// Remove the item from the market
				_marketSalesListDisplay.removeSale(_selectedItem);
				
				// Check quantity
				if (quantity < _selectedItem.quantity)
				{
					// Not all items bought; Split the items between the two lists
					var newItem:GCItem = _selectedItem.split(invItemId, quantity);
					newItem.sellerId = GCPlayState.getPlayerId();
					newItem.sellerName = GCPlayState.getPlayerName();
					newItem.ownerLevel = GCPlayState.playerData.playerLevel;
					newItem.price = 0;
					newItem.isSale = false;
					
					// Load the new item into our ship (for first tutorial, they don't have a ship so add to warehouse)
					(GCPlayState.tutorialSequence.currentTutorialStage > GCTutorial.STAGE_FIRST_ORDER) ?
						_shipInventoryListDisplay.addItem(newItem) : _warehouseListDisplay.addItem(newItem);
					
					// Add the remaining items back into the market
					_marketSalesListDisplay.addSale(_selectedItem);					
				}
				else if (quantity == _selectedItem.quantity)
				{
					// All items are being transferred
					_selectedItem.invItemId = invItemId;
					_selectedItem.sellerId = GCPlayState.getPlayerId();
					_selectedItem.sellerName = GCPlayState.getPlayerName();
					_selectedItem.ownerLevel = GCPlayState.playerData.playerLevel;
					_selectedItem.price = 0;
					_selectedItem.isSale = false;
					
					// Roy-- tutorial, add to warehouse when they still don't have ship yet
					(GCPlayState.tutorialSequence.currentTutorialStage > GCTutorial.STAGE_FIRST_ORDER) ?
						_shipInventoryListDisplay.addItem(_selectedItem) : _warehouseListDisplay.addItem(_selectedItem);
				}
			}
			
			// Clean up the popup
			onBuyCancel();
		}
		
		/**
		 * Will close and clear the buy popup
		 * 
		 * @param	event
		 */
		private function onBuyCancel(event:Event = null):void
		{
			_buyPopup.clearPopup();
			GCPlayState.enableScreen();
		}
		
		/**
		 * Reacts to the sell button
		 * Opens up the popup for selling confirmation
		 */
		private function onSellClick(event:GCEvent):void
		{
			_selectedItemUI = _warehouseListDisplay.selected as GCItemListUI;
			
			if (_selectedItemUI == null)
			{
				// No item Selected; just return and don't open popup
				return;
			}
			
			_selectedItem = _selectedItemUI.reference;
			
			/*
			// Check if item is a sales
			if (_selectedItem.isSale)
			{
				_selectedItemUI = null;
				_selectedItem = null;
				return;
			}*/
			
			// Open up the sell popup
			_sellPopup.initializePopup(_selectedItem.quantity, GCItemData.getNameFromId(_selectedItem.itemId));
			_sellPopup.x = FlxG.width / 2 - _sellPopup.width / 2;
			_sellPopup.y = FlxG.height / 2 - _sellPopup.height / 2;
			GCPlayState.disableScreen(_sellPopup);
		}
		
		/*
		 * Handles when the player successfully confirms a sale
		 * */		
		private function onSellConfirm(event:Event):void
		{
			/*
			Get the quantity they wanted to sell and the
			price per unit they wanted to sell it at.
			*/
			var quantity:int = _sellPopup.quantityToSell;
			var pricePer:int = _sellPopup.pricePerUnit;
			
			// If selling nothing or trying to sell for zero, exit immediately.
			if (quantity == 0 || pricePer == 0)
			{
				onSellCancel();
				return;
			}
			
			// Roy-- tutorial
			if (GCPlayState.tutorialSequence.currentTutorialStage == GCTutorial.STAGE_START_CITY)
			{
				/*
				 * Checking the subgoal, selling enough items
				 */
				if (GCPlayState.tutorialSequence.getTutorialQuestFromTemplate(GCQuestData.QUEST_TEMPLATE_TUTORIAL_0) != null)
				{
					if (!checkSalePriceValid(GCQuestData.QUEST_TEMPLATE_TUTORIAL_0, 10, 25))
					{
						onSellCancel();
						return;
					}
				}
			}
			else if (GCPlayState.tutorialSequence.currentTutorialStage == GCTutorial.STAGE_ON_RETURN)
			{
				if (!checkSalePriceValid(GCQuestData.QUEST_TEMPLATE_TUTORIAL_10, 10, 50))
				{
					onSellCancel();
					return;
				}
			}
			
			if (GCConstants.LOGGING_DATA)
			{
				// Log the transaction
				var o:Object = new Object();
				o["itemId"] = _selectedItem.itemId;
				o["qty"] = _selectedItem.quantity;
				o["price"] = _selectedItem.price;
				GCPlayState.logger.LogAction(new ClientAction(ClientActionType.POST_SALE, o));
			}
			
			//DATABASE CALL- Try to post a brand new sale
			var invItemId:uint = _selectedItem.invItemId;
			
			if (GCConstants.DEBUG_MODE)
			{
				onSellSuccess();
				
				// Clear the selections
				_selectedItem = null;
				_selectedItemUI = null;

				// Clean up the popup
				onSellCancel();
			}
			else
			{
				GCUtil.updateSalesListing(invItemId, quantity, pricePer, function (code:uint, data:Object):void
				{
					// Continue only if the sale was successful
					if (code == 0)
					{
						trace("DATABASE-- Successfully posted a sale.");
						onSellSuccess();
					}
					else if (code == 2)
					{
						GCPlayState.disableScreen(new GCTextPopup("Some one already bought this item!", GCPlayState.enableScreen));
					}
					
					// Clear the selections
					_selectedItem = null;
					_selectedItemUI = null;

					// Clean up the popup
					onSellCancel();
				});
			}
			
			function onSellSuccess():void
			{
				// Remove the item from the warehouse
				_warehouseListDisplay.removeItem(_selectedItem);
				
				// Check the quantity
				if (quantity < _selectedItem.quantity)
				{
					// Not all items transferred; Split the items between the two lists
					var newSale:GCItem = _selectedItem.split(invItemId, quantity);
					newSale.price = pricePer;
					newSale.isSale = true;
					newSale.ownerLevel = GCPlayState.playerData.playerLevel;
					newSale.sellerName = GCPlayState.getPlayerName();
					
					// Load the new item into our sales inventory
					_playerSalesListDisplay.addItem(newSale);
					
					// Add the remaining items back into the warehouse
					_warehouseListDisplay.addItem(_selectedItem);					
				}
				else if(quantity == _selectedItem.quantity)
				{
					// All items are being put up for sale
					_selectedItem.price = pricePer;
					_selectedItem.isSale = true;
					_selectedItem.sellerName = GCPlayState.getPlayerName();
					_selectedItem.ownerLevel = GCPlayState.playerData.playerLevel;
					_playerSalesListDisplay.addItem(_selectedItem);
				}
				
				// For tutorial, immediately try buying the item once a sale has been posted
				tutorialAutoBuy();
			}
		}
		
		/**
		 * Will close and clear the sell popup
		 * 
		 * @param	event
		 */
		private function onSellCancel(event:Event = null):void
		{
			_sellPopup.clearPopup();
			GCPlayState.enableScreen();
		}
		
		private function onRemoveClick(event:GCEvent):void
		{
			_selectedItemUI = _playerSalesListDisplay.selected as GCItemListUI;
			
			if (_selectedItemUI == null)
			{
				// No item selected; Just return and don't open popup
				return
			}
			
			_selectedItem = _selectedItemUI.reference;
			
			var removeConfirmation:GCConfirmationPopup = new GCConfirmationPopup(onRemoveSale);
			removeConfirmation.initializePopup("Are you sure you want to remove this sale?");
			removeConfirmation.addEventListener(GCEvent.CANCEL_EVENT, onCancelRemoveSale);
			GCPlayState.disableScreen(removeConfirmation);
			
			// If player cancels, must reenable the screen
			function onCancelRemoveSale(event:Event):void
			{
				removeConfirmation.removeEventListener(MouseEvent.CLICK, onRemoveSale);
				removeConfirmation.removeEventListener(GCEvent.CANCEL_EVENT, onCancelRemoveSale);
				GCPlayState.enableScreen();
			};
		}
		
		private function onRemoveSale(event:Event):void
		{
			_selectedItemUI = _playerSalesListDisplay.selected;
			
			if (_selectedItemUI == null) 
			{
				// No item selected
				return;
			}
			
			_selectedItem = _selectedItemUI.reference;
			
			if (GCConstants.DEBUG_MODE)
			{
				onFinishListingRemove();
			}
			else
			{
				//DATABASE CALL- Removing a sale listing the player posted earlier
				GCUtil.updateSalesListing(_selectedItem.invItemId, 0, 0, function (code:uint, data:Object):void
				{
					trace("DATABASE-- Successfully removed the sales listing");
					if (code == 0)
					{
						onFinishListingRemove();
					} else if (code == 2)
					{
						GCPlayState.disableScreen(new GCTextPopup("Some one already bought this item!", GCPlayState.enableScreen));
						// Remove the item from the market
						_playerSalesListDisplay.removeItem(_selectedItem);
						
						// All items are being transferred
						_selectedItem.price = 0;
						_selectedItem.isSale = false;
					}
				});
			}
			
			function onFinishListingRemove():void
			{
				// Remove the item from the market
				_playerSalesListDisplay.removeItem(_selectedItem);
				
				// All items are being transferred
				_selectedItem.price = 0;
				_selectedItem.isSale = false;
				_warehouseListDisplay.addItem(_selectedItem);
			}
			
			// Enable Screen again
			GCPlayState.enableScreen();
		}
		
		//----------------------------------------------------------------------
		//	TUTORIAL FUNCTIONS
		//----------------------------------------------------------------------
		
		private function randomSaleGenerator():GCItem
		{
			var fakeInvItemId:uint = 0;
			var requestItemId:uint = Math.floor(Math.random() * 12) + 1;
			var sellerId:uint = GCConstants.COMPUTER_SELLER;
			var sellerName:String = GCConstants.COMPUTER_NAME;
			var quantity:uint = Math.floor(Math.random() * 20) + 1;
			var price:uint = Math.floor(Math.random() * 30) + 50;
			var item:GCItem = new GCItem(fakeInvItemId, requestItemId, quantity, sellerId, sellerName, price, true);
			return item;
		}
		
		/**
		 * Roy-- tutorial
		 * A function to generate a predefined set of sales that the player will buy from as they
		 * are progressing through the tutorial.
		 * 
		 * @param 	id
		 * 		Decide which batch of items to get the sales from
		 */
		private function generateFakeSales(id:uint):Vector.<GCItem>
		{
			var salesList:Vector.<GCItem> = new Vector.<GCItem>();
			var item:GCItem;
			switch(id)
			{
				case GCTutorial.STAGE_START_CITY:
					item = new GCItem(001111, GCItemData.ITEM_FOOD, 23, GCConstants.COMPUTER_SELLER, GCConstants.COMPUTER_NAME, 50, true);
					salesList.push(item);
					item = new GCItem(001112, GCItemData.ITEM_COAL, 19, GCConstants.COMPUTER_SELLER, GCConstants.COMPUTER_NAME, 69, true);
					salesList.push(item);
					item = new GCItem(001113, GCItemData.ITEM_SILVER, 5, GCConstants.COMPUTER_SELLER, GCConstants.COMPUTER_NAME, 130, true);
					salesList.push(item);
					item = new GCItem(001114, GCItemData.ITEM_SALT, 52, GCConstants.COMPUTER_SELLER, GCConstants.COMPUTER_NAME, 44, true);
					salesList.push(item);
					item = new GCItem(001115, GCItemData.ITEM_COAL, 2, GCConstants.COMPUTER_SELLER, GCConstants.COMPUTER_NAME, 8, true);
					salesList.push(item);
					break;
				case GCTutorial.STAGE_FIRST_ORDER:
					item = new GCItem(001101, GCItemData.ITEM_LUMBER, 20, GCConstants.COMPUTER_SELLER, GCConstants.COMPUTER_NAME, 8, true);
					salesList.push(item);
					item = new GCItem(001102, GCItemData.ITEM_LUMBER, 10, GCConstants.COMPUTER_SELLER, GCConstants.COMPUTER_NAME, 5, true);
					salesList.push(item);
					break;
				case GCTutorial.STAGE_FIRST_JOURNEY:
					item = new GCItem(001103, GCItemData.ITEM_FOOD, 25, GCConstants.COMPUTER_SELLER, GCConstants.COMPUTER_NAME, 10, true);
					salesList.push(item);
					item = new GCItem(001104, GCItemData.ITEM_IRON, 10, GCConstants.COMPUTER_SELLER, GCConstants.COMPUTER_NAME, 15, true);
					salesList.push(item);
					break;
				case GCTutorial.STAGE_AT_NEW_CITY:
					item = new GCItem(001105, GCItemData.ITEM_FOOD, 15, GCConstants.COMPUTER_SELLER, GCConstants.COMPUTER_NAME, 23, true);
					salesList.push(item);
					item = new GCItem(001106, GCItemData.ITEM_COTTON, 20, GCConstants.COMPUTER_SELLER, GCConstants.COMPUTER_NAME, 8, true);
					salesList.push(item);
					break;
			}
			return salesList;
		}
		
		/**
		 * Roy-- tutorial
		 * During stages where game buys the player's sales, we must restrict the
		 * price range at which they sell.
		 * 
		 */
		private function checkSalePriceValid(templateId:uint, minPrice:uint, maxPrice:uint):Boolean
		{
			trace("GCMarketMenu-- checking if being sold!");
			var text:String;
			if (_sellPopup.pricePerUnit < minPrice)
			{
				text = "That is a bit too low, try setting a higher price! Try between " + String(minPrice) + " to " + String(maxPrice) + " gold per unit.";
				GCPlayState.disableScreen(new GCTextPopup(text, GCPlayState.enableScreen));
			}
			
			if (_sellPopup.pricePerUnit > maxPrice)
			{
				text = "That is a bit too high, try setting a lower price! Try between " + String(minPrice) + " to " + String(maxPrice) + " gold per unit.";
				GCPlayState.disableScreen(new GCTextPopup(text, GCPlayState.enableScreen));
			}
			
			return (_sellPopup.pricePerUnit >= minPrice && _sellPopup.pricePerUnit <= maxPrice && _sellPopup.quantityToSell > 0);
		}
		
		/**
		 * Roy-- tutorial
		 * A function to check if a player has bough the specified amount of goods
		 * from the market.
		 * 
		 * @param	boughtItemId
		 * 			The id of the good that was actually bought, if different than
		 * 			the one we want, we can exit early
		 */
		private function checkIfEnoughBought(templateId:uint, boughtItemId:uint):void
		{
			/*
			* Here we must check that they have bough enough of the specified goods to fulfill the first
			* NPC buy order.
			*/
			var quest:GCQuest = GCPlayState.tutorialSequence.getTutorialQuestFromTemplate(templateId);
			if (quest != null && quest.goalId == boughtItemId)
			{
				var desiredItem:uint = quest.goalId;
				var amountNeeded:uint = quest.goalQuantity;
				var warehouseInv:GCInventory = GCPlayState.getCurrentCity().getInventoryFromCity();
				var shipInv:GCInventory = GCPlayState.getPlayerInventory();
				
				// Get the item object for the desired goal item
				var itemObj:GCItem;
				
				// If its before they have access to ship, check their warehouse for bought item, otherwise check their
				// ship, since at that point all buys go there.
				itemObj = (GCPlayState.tutorialSequence.currentTutorialStage > GCTutorial.STAGE_FIRST_ORDER) ?
					shipInv.getItemFromId(desiredItem) : warehouseInv.getItemFromId(desiredItem);
				trace("Checking if bought enough " + GCItemData.getNameFromId(desiredItem));
				
				if (itemObj != null && itemObj.quantity >= amountNeeded)
				{
					GCPlayState.dispatchTutorialComplete(templateId);
				}
			}
		}
		
		private function tutorialAutoBuy():void
		{
			// Roy-- tutorial
			if (GCPlayState.tutorialSequence.currentTutorialStage == GCTutorial.STAGE_START_CITY)
			{
				var templateId:uint;
				var quest:GCQuest;
				var buyTimer:Timer;
				/*
				 * Checking the subgoal, selling enough items.
				 * For this goal we will check
				 */
				templateId = GCQuestData.QUEST_TEMPLATE_TUTORIAL_0;
				quest = GCPlayState.tutorialSequence.getTutorialQuestFromTemplate(templateId)
				if (quest != null)
				{
					//trace("GCMarketMenu-- checking if being sold!");
					buyTimer = new Timer(1000, 1);
					buyTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onAutoBuy);
					
					buyTimer.start();
					
					/*
					 * Automatically buy the goods after the player leaves the market.
					 */
					function onAutoBuy(event:TimerEvent):void
					{
						buyTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onAutoBuy);
						
						var goldEarned:uint = autoBuyPlayerGoods();
						
						if (goldEarned > 0)
						{
							// Give gold based on sale
							GCPlayState.changePlayerGold(goldEarned);
						}
						
						/*
						 * Check if the player has made enough gold from sales to progress to
						 * complete this goal.
						 */
						if (GCPlayState.getPlayerGold() >= quest.goalQuantity)
						{
							GCPlayState.dispatchTutorialComplete(GCQuestData.QUEST_TEMPLATE_TUTORIAL_0);
						}
					}
				}
			}
			else if (GCPlayState.tutorialSequence.currentTutorialStage == GCTutorial.STAGE_ON_RETURN)
			{
				/*
				* Checking the subgoal, selling enough items.
				* For this goal we will check
				*/
				templateId = GCQuestData.QUEST_TEMPLATE_TUTORIAL_10;
				quest = GCPlayState.tutorialSequence.getTutorialQuestFromTemplate(templateId);
				
				// Only auto buy in the tutorial stages at picaroon (other places, they do not have a warehouse)
				if (GCPlayState.getCurrentCity().getId() == GCCityData.CITY_PICAROON)
				{
					trace("GCMarketMenu-- checking if being sold!");
					buyTimer = new Timer(1000, 1);
					buyTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onBuy);
					
					buyTimer.start();
					
					/*
					* Automatically buy the goods after the player leaves the market.
					*/
					function onBuy(event:TimerEvent):void
					{
						buyTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onBuy);
						
						var goldEarned:uint = autoBuyPlayerGoods();
						
						if (goldEarned > 0)
						{
							// Give gold and xp based on sale
							GCPlayState.changePlayerGold(goldEarned);
							(quest != null) ? GCPlayState.dispatchTutorialComplete(templateId) : GCPlayState.increaseExperience(200);
							
							refresh();
						}
					}
				}
			}
		}
		
		/**
		 * Automatically buy player goods on sale, returns the amount of
		 * gold they made from the sale.
		 * 
		 * @return
		 */
		private function autoBuyPlayerGoods():uint
		{
			var playerSales:GCInventory = GCPlayState.getCurrentCity().getSalesFromCity();
			var goldEarned:uint = 0;
			for (var obj:Object in playerSales.inventory)
			{
				var itemId:uint = obj as uint;
				var itemObj:GCItem = playerSales.inventory[itemId];
				
				goldEarned += itemObj.price * itemObj.quantity;
				
				onUpdateListing(itemId, itemObj);
			}
			
			function onUpdateListing(itemId:uint, itemObject:GCItem):void
			{
				if (GCConstants.DEBUG_MODE)
				{
					GCPlayState.addNewnotification("Items were sold " + GCItemData.getNameFromId(itemId) + ", " + String(itemObject.quantity) + " for " + String(itemObject.price * itemObject.quantity));
					playerSales.removeFromInventory(itemId, itemObject.quantity);
				}
				else
				{
					//DATABASE CALL- Auto buy need to remove the sale listing and also remove the
					// quantity from the player's inventory
					GCUtil.updateSalesListing(itemObject.invItemId, 0, 0, function(code:uint, data:Object):void
					{
						var availableItem:GCItem = GCPlayState.getCurrentCity().getInventoryFromCity().getItemFromId(itemId);
						var totalLeftover:uint = (availableItem == null) ? 0 : availableItem.quantity;
						
						trace("Automatically bought item and updated " + itemObj.quantity);
						GCUtil.updateItemQuantity(itemObject.invItemId, totalLeftover, function(code:uint, data:Object):void
						{
							trace("Automatically bought item and updated quantity");
						});
						GCPlayState.addNewnotification("Items were sold " + GCItemData.getNameFromId(itemId) + ", " + String(itemObject.quantity) + " for " + String(itemObject.price * itemObject.quantity));
						playerSales.removeFromInventory(itemId, itemObject.quantity);
					});
				}
			}
			
			return goldEarned;
		}
		
		//----------------------------------------------------------------------
		//	SUPER MENU FUNCTIONS
		//----------------------------------------------------------------------
		
		/**
		 * Updates the current lists on display
		 */
		public function refresh():void
		{
			_shipInventoryListDisplay.redraw();
			_warehouseListDisplay.redraw();
			_playerSalesListDisplay.redraw();
			_marketSalesListDisplay.redraw();
		}
		
		/**
		 * Method to enable list displays to scroll
		 */
		public function enableScrolling():void
		{
			_shipInventoryListDisplay.scrollEnable();
			_warehouseListDisplay.scrollEnable();
			_playerSalesListDisplay.scrollEnable();
			_marketSalesListDisplay.scrollEnable();			
		}
		
		/**
		 * Method to disable list displays from scrolling
		 */
		public function disableScrolling():void
		{
			_shipInventoryListDisplay.scrollDisable();
			_warehouseListDisplay.scrollDisable();
			_playerSalesListDisplay.scrollDisable();
			_marketSalesListDisplay.scrollDisable();
		}
				
		
	}
}
			
			